package com.zijidelu.luframework.generator;

import cn.hutool.core.util.StrUtil;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseResult;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.stmt.BlockStmt;
import com.github.javaparser.printer.lexicalpreservation.LexicalPreservingPrinter;
import com.zijidelu.luframework.base.bizsig.BizSignatureConditionBuilder;
import com.zijidelu.luframework.utils.CastUtil;
import com.zijidelu.luframework.utils.io.PathUtil;
import com.zijidelu.luframework.utils.lang.reflect.generic.GenericResolveUtil;
import com.zijidelu.luframework.base.bizsig.BizSignature;
import com.zijidelu.luframework.base.bizsig.FieldDescriptor;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 业务签名构建器的生成器。
 *
 * @author ZIJIDELU
 * @datetime 2025/10/24 11:21
 */
@Slf4j
public class BizSigBuilderGenerator {
    private final BizSignature<?> bizSignature;
    private final Class<?> bizSigClass;
    private final Class<?> entityClass;
    private final String bizSigName;

    private BizSigBuilderGenerator(BizSignature<?> bizSignature, String bizSigName) {
        this.bizSignature = bizSignature;
        this.bizSigClass = bizSignature.getClass();
        if (bizSigName.contains("_")) {
            this.bizSigName = StrUtil.upperFirst(StrUtil.toCamelCase(bizSigName));
        } else {
            this.bizSigName = StrUtil.upperFirst(StrUtil.toLowerCase(bizSigName));
        }
        if (!Enum.class.isAssignableFrom(bizSigClass)) {
            throw new IllegalArgumentException("Biz Signature class must be an enum");
        }

        List<Type> generics = GenericResolveUtil.resolveGenerics(bizSigClass, BizSignature.class);
        this.entityClass = GenericResolveUtil.getRawType(generics.getFirst());
    }

    /**
     * 生成业务签名构建器。
     */
    public void builderBizSigBuilder() {
        List<? extends FieldDescriptor<?>> fieldDescriptorList = bizSignature.getFieldDescriptorList();

        String bizSigBuilderName = bizSigClass.getSimpleName() + bizSigName + "Builder";

        Map<String, Object> root = new HashMap<>();

        root.put("package", bizSigClass.getPackageName());
        root.put("bizSignatureConditionBuilderClassName", BizSignatureConditionBuilder.class.getName());
        root.put("entityClassName", entityClass.getName());
        root.put("entityClassSimpleName", entityClass.getSimpleName());
        root.put("bizSigBuilderName", bizSigBuilderName);
        root.put("fieldDescriptorList", fieldDescriptorList);

        Configuration ftlConfiguration = FreeMarkerFactory.getFtlConfiguration();
        // 计算业务签名类的绝对路径
        Path bizSigClassRealPath = PathUtil.calcClassRealPath(bizSigClass);
        // 业务签名类的绝对路径的父目录
        Path bizSigClassRealPathParent = bizSigClassRealPath.getParent();
        // 业务签名构建器的绝对路径
        String bizSigBuilderAbsolutePath = bizSigClassRealPathParent.resolve(bizSigBuilderName + ".java").toString();
        File bizSigBuilderParentFile = bizSigClassRealPathParent.toFile();
        if (!bizSigBuilderParentFile.exists()) {
            log.info("Create Biz Signature Builder Parent File: {}", bizSigBuilderParentFile.getAbsolutePath());
            bizSigBuilderParentFile.mkdirs();
        }
        try (FileWriter fw = new FileWriter(bizSigBuilderAbsolutePath)) {
            // 生成业务签名构建器类
            log.info("Generate Biz Signature Builder: {}", bizSigBuilderAbsolutePath);
            Template template = ftlConfiguration.getTemplate("BizSigBuilder.ftl");
            template.process(root, fw);

            // 写入业务签名获取构建器方法
            // 1. 解析Java文件
            // 定位源文件
            Path bizsigPath = bizSigClassRealPathParent.resolve(bizSigClass.getSimpleName() + ".java");
            JavaParser javaParser = new JavaParser();
            ParseResult<CompilationUnit> parseResult = javaParser.parse(bizsigPath.toFile());
            CompilationUnit cu = parseResult.getResult().get();
            // 保持原有Java文件的格式
            LexicalPreservingPrinter.setup(cu);
            // 2. 查找目标类
            cu.getEnumByName(bizSigClass.getSimpleName()).ifPresent(enumDecl -> {
                // 3. 创建新方法
                MethodDeclaration newMethod = new MethodDeclaration();
                newMethod.setName("get" + bizSigBuilderName);
                newMethod.setType(bizSigBuilderName);
                newMethod.setPublic(true);
                newMethod.setStatic(true);

                // 4. 添加方法体
                BlockStmt body = new BlockStmt();
                body.addStatement(String.format("return %s.builder();", bizSigBuilderName));
                newMethod.setBody(body);

                // 5. 将方法添加到类
                enumDecl.addMember(newMethod);
            });

            // 6.1 配置PrettyPrinter以保留原始格式
            String modifiedContent = LexicalPreservingPrinter.print(cu);

            // 6.2 保存修改后的Java文件
            try (OutputStreamWriter writer = new OutputStreamWriter(
                    new FileOutputStream(bizsigPath.toFile()), StandardCharsets.UTF_8)) {

                writer.write(modifiedContent);
                log.info("Biz Signature Add Builder Function Success: {}", "get" + bizSigBuilderName);
            }

        } catch (IOException | TemplateException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 创建业务签名构建器。
     *
     * @param bizSigClass 业务签名类
     */
    public static void generate(Class<? extends BizSignature<?>> bizSigClass) {
        Object[] enumConstants = bizSigClass.getEnumConstants();

        if (enumConstants.length == 0) {
            throw new IllegalArgumentException("Biz Signature enum must have at least one constant");
        }

        for (Object enumConstant : enumConstants) {
            new BizSigBuilderGenerator(CastUtil.cast(enumConstant), enumConstant.toString()).builderBizSigBuilder();
        }
    }

}
